from tkinter import filedialog
from tkinter import scrolledtext
from tkinter.filedialog import askdirectory
import tkinter as tk
import tkinter.ttk
import threading
import paramiko
import datetime
import calendar
import pathlib
import json
import time
import os
import re


def get_provinces(json_path):
    with open(json_path, "r", encoding="utf-8") as json_file:
        china_tiles = json.load(json_file)
    return china_tiles


# ui
class ui:

    # defult_json_path = r"E:\PythonProjcet\RasterShapeToolBox\conf\ChinaMgrs.json"
    defult_remote_folder = r"/home/万裕青/遥感数据/Sentinel2L1cZip"
    width, height = 800, 980
    line_height = 60
    bands = ["2", "3", "4", "5", "6", "7", "8",  "12"]
    txt_path = os.path.join(os.getcwd(),"history.txt")
    provinces = []

    def __init__(self):
        
        self.get_window()
        self.bands_default_value = tk.StringVar()
        self.tiles_str = tk.StringVar()
        self.tif_folder = tk.StringVar()
        self.json_path = tk.StringVar()
        # self.json_path.set()
        self.remote_folder = tk.StringVar()
        self.remote_folder.set(self.defult_remote_folder)
        line_iter = iter(range(50))

        self.sentinel_frame(next(line_iter))
        self.jsonfile_frame(next(line_iter))
        self.province_frame(next(line_iter))
        self.yearmonth_frame(next(line_iter))
        self.cloud_frame(next(line_iter))
        self.bands_frame(next(line_iter))
        self.remote_folder_frame(next(line_iter))
        self.local_folder_frame(next(line_iter))
        self.start_button_frame(next(line_iter))
        self.progressbar_frame(next(line_iter))
        self.print_running_frame(next(line_iter))

        self.window.mainloop()

    def get_window(self):
        self.window = tk.Tk()
        self.window.title('Sentinel-2数据下载工具')
        screenwidth = self.window.winfo_screenwidth() # 屏幕宽度
        screenheight = self.window.winfo_screenheight() # 屏幕高度
        x = int((screenwidth - self.width) / 2)
        y = int((screenheight - self.height) / 2)
        locat = f"{self.width}x{self.height}+{x}+{y}"
        self.window.geometry(locat) # 大小以及位置
        # self.window.geometry('800x700')
        return

    def sentinel_frame(self, row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        column_iter = iter(range(10))

        tk.Label(
            frame,text="图幅列表",font=('宋体','14','bold'),height=3,
        ).grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)

        frame2 = tkinter.ttk.Frame(frame)
        frame2.grid(column=1,row=0,sticky=tk.W+tk.E)

        self.tilestr_entry=tk.Entry(
            frame2,
            width=63,
            background = 'white',
            borderwidth = 3,
            relief = 'sunken',
            insertwidth = 3,
            font = ('Helvetica', '14', 'bold'),
            textvariable=self.tiles_str,
            selectforeground = 'red',
            selectbackground = 'blue',
            selectborderwidth = 3,
            show=None)
        self.tilestr_entry.pack(side=tk.TOP,fill=tk.NONE) 

        scroll = tk.Scrollbar(
            frame2,
            orient=tk.HORIZONTAL,
            cursor="arrow",
            command=self.tilestr_entry.xview,
            # width=85
        )
        scroll.pack(side=tk.BOTTOM,fill=tk.X, padx=0)
        self.tilestr_entry.config(xscrollcommand=scroll.set)

        return

    def jsonfile_frame(self, row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        column_iter = iter(range(10))
        tk.Label(
            frame,text="配置文件",font=('宋体','14','bold'),height=3,
         ).grid(column=next(column_iter),row=0,sticky='we')

        self.jsonfile_entry=tk.Entry(
            frame,
            width=74,
            background = 'white',
            borderwidth = 3,
            relief = 'sunken',
            insertwidth = 3,
            font = ('宋体', '12', ''),
            textvariable=self.json_path,
            selectforeground = 'red',
            selectbackground = 'blue',
            selectborderwidth = 0,
            show=None, 
        )
        self.jsonfile_entry.grid(column=next(column_iter),row=0,sticky='we')

        self.select_file_button=tk.Button(
            frame,
            text="选择文件",
            font=('','14','bold'), 
            bg="#50b7c1",
            # command=self.update_config
            command=lambda: self.update_config()
        ) 
        self.select_file_button.grid(column=next(column_iter),row=0,sticky='we')
        return

    def update_config(self):
        self.json_path.set(filedialog.askopenfilename(filetypes=[("配置文件", [".json",] )]))
        chinas = get_provinces(self.json_path.get())
        self.provinces = list(chinas.keys())
        self.province_combobox['value']=self.provinces
        self.province_combobox['height']=len(self.provinces)
        return

    def province_frame(self, row):
        frame=tkinter.ttk.Frame(self.window)
        frame.place(x=0,y=self.line_height*row)
        column_iter = iter(range(10))
        tk.Label(
            frame,text="选择省份",font=('宋体','14','bold'),height=3,
        ).grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)

        self.province_combobox=tkinter.ttk.Combobox(
            frame,
            # width=6,
            height=len(self.provinces),
            state='readonly',
            cursor="arrow",
            background = 'white',
            textvariable="",
            font = ('', '12', ''),
            values=self.provinces,
            show=None
        )
        self.province_combobox.grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)
        return

    def yearmonth_frame(self, row):
        frame=tkinter.ttk.Frame(self.window)
        frame.place(x=0,y=self.line_height*row)
        column_iter = iter(range(10))
        tk.Label(
            frame,text="选择年月",font=('宋体','14','bold'),height=3,
        ).grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)
  
        years = tuple(range(2017,datetime.datetime.now().year+1))
        self.year_combobox=tkinter.ttk.Combobox(
            frame,
            width=4,
            height=len(years),
            state='readonly',
            cursor="arrow",
            background = 'white',
            textvariable="",
            font = ('', '12', ''),
            values=years,
            show=None
        )
        self.year_combobox.grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)
        tk.Label(
            frame,text="年",font=('宋体','14','bold'),height=3,
        ).grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)

        months = tuple(range(1,13))
        self.month_combobox=tkinter.ttk.Combobox(
            frame,
            width=2,
            height=len(months),
            state='readonly',
            cursor="arrow",
            background = 'white',
            textvariable="",
            font = ('', '12', ''),
            values=months,
            show=None
        )
        self.month_combobox.grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)
        tk.Label(
            frame, text="月",font=('宋体','14','bold'),height=3,
        ).grid(column=next(column_iter),row=0,sticky=tk.W+tk.E)
        return

    def cloud_frame(self, row):
        frame=tkinter.ttk.Frame(self.window)
        frame.place(x=0,y=self.line_height*row)
        tk.Label(
            frame,text=f"最大云量",font=('宋体','14','bold'),height=3,
        ).grid(column=0,row=0,sticky='we')
        max_clound = tk.IntVar()
        max_clound.set(100)
        self.maxcloud_scale=tk.Scale(
            frame, 
            # label="MaxCloud",    # 标签
            variable=max_clound, 	# 值
            from_=0,    #  最小值， 记住是from_， from是关键字
            to=100,       #  最大值
            resolution=1,  # 步进值
            show=True,   # 是否在上面显示值
            orient=tk.HORIZONTAL,  # 水平显示
            length=680,  # 滑块长度
            # command=lambda value, key=k:self.get_value(value, key)
        )
        self.maxcloud_scale.grid(column=1,row=0,sticky='we')
        return
   
    def bands_frame(self, row):
        frame=tkinter.ttk.Frame(self.window)
        frame.place(x=0,y=self.line_height*row)
        tk.Label(
            frame,text="波段列表",font=('宋体','14','bold'),height=3,
        ).grid(column=0,row=0,sticky='we')
        bands = tk.StringVar()
        bands.set("2-3-4-5-6-7-8-12")
        self.bands_entry=tk.Entry(
            frame,
            width=51,
            background = 'white',
            borderwidth = 3,
            relief = 'sunken',
            insertwidth = 3,
            font = ('', '12', ''),
            textvariable=bands,
            selectforeground = 'red',
            selectbackground = 'blue',
            selectborderwidth = 0,
            # show="2-3-4-5-6-7-8-8A-11-12-99"
        )
        self.bands_entry.grid(column=1,row=0,sticky='we')
        return

    def remote_folder_frame(self, row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        tk.Label(
            frame,text="远程目录",font=('宋体','14','bold'),height=3
        ).grid(column=0,row=0,sticky='we')  #定义一个标签lable
        self.remote_dir=tk.Entry(
            frame,
            width=53,
            background = 'white',
            borderwidth = 3,
            relief = 'sunken',
            insertwidth = 3,
            font = ('', '14', 'bold'),
            textvariable=self.remote_folder,
            selectforeground = 'red',
            selectbackground = 'blue',
            selectborderwidth = 0,
            show=None
        )  
        self.remote_dir.grid(column=1,row=0,sticky='we')
        return

    def local_folder_frame(self, row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        tk.Label(
            frame,text="本地目录",font=('宋体','14','bold'),height=3
        ).grid(column=0,row=0,sticky='we')  #定义一个标签lable
        self.local_dir=tk.Entry(
            frame,
            width=53,
            background = 'white',
            borderwidth = 3,
            relief = 'sunken',
            insertwidth = 3,
            font = ('Helvetica', '14', 'bold'),
            textvariable=self.tif_folder,
            selectforeground = 'red',
            selectbackground = 'blue',
            selectborderwidth = 0,
            show=None
        )  
        self.local_dir.grid(column=1,row=0,sticky='we')
        self.select_dir_button=tk.Button(
            frame,
            text="选择目录",
            font=('','14','bold'), 
            bg="#50b7c1",
            command=lambda: self.tif_folder.set(askdirectory().replace('/','\\')),
        ) 
        self.select_dir_button.grid(column=2,row=0,sticky='we')
        return

    def start_button_frame(self, row):
        s = tkinter.ttk.Style()
        s.configure("1.TFrame",background='white')
        frame=tkinter.ttk.Frame(
            self.window,style="1.TFrame",width=self.width,height=60)
        frame.place(x=0,y=self.line_height*row)
        self.start_button=tk.Button(
            frame,
            text="开始下载",
            font=('','14','bold'),
            bg="#50b7c1",
            command=lambda: self.thread_it(self.run_main),
        )
        self.start_button.place(relx=0.5,rely=0.5,anchor='center')
        return

    def thread_it(self,func,*args):
        t = threading.Thread(target=func, args=args)
        # 守护 !!!
        t.setDaemon(True)
        # 启动
        t.start()
        # 阻塞--卡死界面！
        # t.join()
        return

    def progressbar_frame(self,row):
        frame=tkinter.ttk.Frame(self.window)
        frame.place(x=0,y=60*row)
        tk.Label(
            frame,text="运行进度",font=('宋体','14','bold'),height=3,
        ).grid(column=0,row=0,sticky='we')
        self.progressbar=tkinter.ttk.Progressbar(
            frame,
            length=680,
            # maximum=100,
            value=0,
            cursor='spider',
            mode="determinate",
            # mode="indeterminate",
            orient=tk.HORIZONTAL,
        )
        self.progressbar.grid(column=1,row=0,sticky='we')
        return

    def print_running_frame(self, row):
        frame=tkinter.ttk.Frame(self.window)
        frame.place(x=0,y=60*row)
        tk.Label(
            frame,text="运行信息",font=('宋体','14','bold'),
        ).grid(column=0,row=0,sticky='we')
        # ).pack(side=tk.LEFT+tk.TOP,fill=tk.NONE)
        self.scrolled_text = scrolledtext.ScrolledText(
			frame, 
			state='normal',
            wrap = tk.WORD,
            # font=('Times New Roman', 12),
            font="TkFixedFont",
			width=95, 
			height=28,
        ) 
        self.scrolled_text.tag_config('INFO', foreground='black')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING', foreground='orange')
        self.scrolled_text.tag_config('ERROR', foreground='red')
        self.scrolled_text.tag_config('CRITICAL', foreground='red', underline=1)
        self.scrolled_text.grid(column=1,row=0,rowspan=20,sticky='we')
        # self.scrolled_text.pack(side=tk.LEFT,fill=tk.NONE) 
        return
    
    def update_info(self,string):
        datetime_str = datetime.datetime.now().strftime('%H:%M:%S')
        string = f"{datetime_str}>{string} \n"
        self.scrolled_text.insert(tk.END, string)
        self.scrolled_text.see(tk.END)
        self.scrolled_text.focus()
        self.window.update()
        return

    def run_main(self):
        start = time.time()
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.delete(0.0, tkinter.END)
        self.window.update()

        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(hostname="192.168.2.172",port=22,username="root",password="DELL123dell")
        sftp: paramiko.SFTPClient = client.open_sftp()
        self.update_info("连接服务器:192.168.2.172")

        tiles_str = self.tilestr_entry.get()
        if tiles_str!="":
            tiles = [tile.upper() for tile in tiles_str.split("-")]
        else:
            province = self.province_combobox.get()
            china_tiles = get_provinces(self.json_path.get())
            tiles = china_tiles[province]
        if not tiles:
            tk.messagebox.showwarning('Waring', '未选择图幅！')
            return
        self.update_info(f"{len(tiles)}个图幅:{tiles}")
     
        year = int(self.year_combobox.get())
        month = int(self.month_combobox.get())

        if not (year and month):
            tk.messagebox.showerror('Error', '时期未选择完整！')
            return
        days = calendar.monthrange(year,month)[1]
        dates = [datetime.date(year,month,day) for day in range(1,days+1)]
        self.update_info(f"日期:{year}-{month}")

        maxclound = self.maxcloud_scale.get()
        self.update_info(f"最大含云量:{maxclound}")

        bands_str = self.bands_entry.get()
        if bands_str == "":
            tk.messagebox.showerror('Error', '未选择存在波段！')
            return
        bands = bands_str.split("-")
        self.update_info(f"波段列表:{bands}")
    
        remote_dir = self.remote_dir.get()
        if remote_dir == "":
            tk.messagebox.showerror('Error', '未选择远程目录！')
            return
        self.update_info(f"远程目录:{remote_dir}")

        local_dir = self.local_dir.get()
        if local_dir == "":
            tk.messagebox.showerror('Error', '未选择本地目录！')
            return
        self.update_info(f"本地目录:{local_dir}")

        remote_files = []
        for date in dates:
            date_str = date.strftime("%Y%m%d")
            date_dir = pathlib.PurePosixPath(remote_dir,date_str)
            try:
                sftp.stat(str(date_dir))
                for file_name in sftp.listdir(str(date_dir)):
                    if re.match(f"S2.*_{date_str}T.*\.zip$",file_name):
                        if file_name.split("_")[5][1:] in tiles:
                            self.update_info(f"exits:{file_name}")
                            path = str(pathlib.PurePosixPath(str(date_dir),file_name))
                            remote_files.append(path)
            except IOError:
                self.update_info(f"{str(date_dir)} 不存在！")

        self.progressbar["maximum"] = len(remote_files)
        for index,path in enumerate(remote_files):
            name = os.path.basename(path)
            self.temp_file_name = name
            local_path = os.path.join(local_dir,name)
            self.progressbar["value"] = index + 1
            if not os.path.exists(local_path):
                sftp.get(path,local_path,callback=self._Callback)
                self.update_info(f"完成下载:{name}")
       
        sftp.close()
        client.close()
        tk.messagebox.showinfo('Message', f'下载完成！耗时：{time.time()-start}')
        return

    def _Callback(self,a=10,b=10):
        percent = round(a*100./int(b),2)
        datetime_str = datetime.datetime.now().strftime('%H:%M:%S')
        if  percent in [i*20.00 for i in range(6)] :
            index = float(self.scrolled_text.index(tk.END))
            self.scrolled_text.delete(index-2.0,index)
            string = f'\n{datetime_str}>{self.temp_file_name} {round(a/1024./1024,2)}M {percent}%\n'
            self.scrolled_text.insert(index, string)
            self.scrolled_text.see(index)
            self.window.update()
        return

if __name__ == "__main__":
    ui()